Abstract Factory Pattern
Previously we learn JAVA - Factory
Pattern
The Abstract Factory is known as a creational
pattern - it's used to construct objects such that they can be decoupled from
the implementing system.
The pattern is best utilized when your system
has to create multiple families of products or you want to provide a library of
products without exposing the implementation details. As you'll have noticed, a
key characteristic is that the pattern will decouple the concrete classes from
the client.
Provides an interface for creating families of
related or dependent objects without specifying their concrete classes.
The AbstractFactory class is the one that
determines the actual type of the concrete object and creates it, but it
returns an abstract pointer to the concrete object just created.
One of the main benefits of this pattern is that the client is totally
decoupled from the concrete products. Also, new product families can be easily
added into the system, by just adding in a new type of ConcreteFactory that
implements AbstractFactory, and creating the specific Product implementations.
Implementing
an Example:
We are going to create a Shape and Color
interfaces and concrete classes implementing these interfaces. We create an
abstract factory class AbstractFactory. Factory classes ShapeFactory and
ColorFactory are defined where each factory extends AbstractFactory. A factory
creator/generator class FactoryProducer is created.
Our demo class uses FactoryProducer to get a
AbstractFactory object. It will pass information (CIRCLE / RECTANGLE / SQUARE
for Shape) to AbstractFactory to get the type of object it needs. It also
passes information (RED / GREEN / BLUE for Color) to AbstractFactory to get the type
of object it needs.
Create an
interface for Shapes.
// Shape.java
public interface Shape{
void draw();
}
Create concrete
classes implementing the same interface.
// Circle.java
public class Circle implements Shape{
@Override
public void draw(){
// TODO
Auto-generated method stub
System.out.println("Inside Circle: draw() method.");
}
}
// Square.java
public class Square implements Shape{
@Override
public void draw(){
// TODO
Auto-generated method stub
System.out.println("Inside Square: draw() method.");
}
}
//
Rectangle.java
public class Rectangle implements Shape{
@Override
public void draw(){
// TODO
Auto-generated method stub
System.out.println("Inside Rectangle: draw() method.");
}
}
Create an interface for Colors.
// Color.java
public interface Color{
void fill();
}
Create concrete classes implementing the same interface.
// Blue.java
public class Blue implements Color{
@Override
public void fill() {
// TODO
Auto-generated method stub
System.out.println("Inside Blue: fill() method.");
}
}
// Green.java
public class Green implements Color{
@Override
public void fill() {
// TODO
Auto-generated method stub
System.out.println("Inside Green: fill() method.");
}
}
// Red.java
public class Red implements Color{
@Override
public void fill() {
// TODO
Auto-generated method stub
System.out.println("Inside Red: fill() method.");
}
}
Create an Abstract class to get factories for Color and Shape Objects.
// AbstractFactory
public abstract class AbstractFactory{
abstract Shape getShape(String shape);
abstract
Color getColor(String color);
}
Create Factory classes extending AbstractFactory to generate object of concrete class based on given information.
// ShapeFactory.java
public class ShapeFactory extends AbstractFactory{
@Override
Shape getShape(String shapeType) {
// TODO
Auto-generated method stub
if(shapeType == null){
return null;
}
if(shapeType.equalsIgnoreCase("CIRCLE")){
return new Circle();
}else if(shapeType.equalsIgnoreCase("RECTANGLE")){
return new Rectangle();
}else if(shapeType.equalsIgnoreCase("SQUARE")){
return new Square();
}
return null;
}
@Override
Color getColor(String color) {
// TODO
Auto-generated method stub
return null;
}
}
// ColorFactory.java
public class ColorFactory extends AbstractFactory{
@Override
Shape getShape(String shape) {
// TODO
Auto-generated method stub
return null;
}
@Override
Color getColor(String color) {
// TODO
Auto-generated method stub
if(color == null){
return null;
}
if(color.equalsIgnoreCase("RED")){
return new Red();
}else if(color.equalsIgnoreCase("GREEN")){
return new Green();
}else if(color.equalsIgnoreCase("BLUE")){
return new Blue();
}
return null;
}
}
Create a Factory generator/producer class to get factories by passing an information such as Shape or Color
// FactoryProducer
public class FactoryProducer {
public static AbstractFactory
getFactory(String choice){
if(choice.equalsIgnoreCase("SHAPE")){
return new ShapeFactory();
}else if(choice.equalsIgnoreCase("COLOR")){
return new ColorFactory();
}
return null;
}
}
Use the FactoryProducer to get AbstractFactory in order to get factories of concrete classes by passing an information such as type.
// AbstractFactoryPatternDemo.java
public class AbstractFactoryPatternDemo {
public static void main(String[]
args){
//.......get shape factory........
AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE");
// get an object of Shape Circle
Shape shape1 =
shapeFactory.getShape("CIRCLE");
// call draw method of Shape Circle
shape1.draw();
// get an object of Shape Rectangle
Shape shape2 =
shapeFactory.getShape("RECTANGLE");
// call draw method of Shape Rectangle
shape2.draw();
// get an object of Shape Square
Shape shape3 =
shapeFactory.getShape("SQUARE");
// call draw method of Shape Square
shape3.draw();
//.........get color factory..........
AbstractFactory
colorFactory = FactoryProducer.getFactory("COLOR");
//get an object of Color Red
Color color1 =
colorFactory.getColor("RED");
// call fill method of Red
color1.fill();
//get an object of Color Green
Color color2 =
colorFactory.getColor("GREEN");
// call fill method of Green
color2.fill();
//get an object of Color Blue
Color color3 =
colorFactory.getColor("BLUE");
// call fill method of Blue
color3.fill();
}
}
Verify the
output.

Watch Out for the Downsides:
While the pattern does a great job of hiding implementation details from the client, there is always a chance that the underlying system will need to change. We may have new attributes to our AbstractProduct, or AbstractFactory, which would mean a change to the interface that the client was relying on, thus breaking the API.
Leave Comment